//#include <ode\ode.h>
#include "level.h"
#include "game.h"
#include "meshscenenode.h"
//#pragma comment(lib, "ode.lib")

Level::Level()
	: Resource()
{
	scene = new Scene();
	playerNode = NULL;
}

Level::~Level()
{
	delete scene;
	if(playerNode)
		delete playerNode;
}

void Level::render()
{
	// odswierz bryly otaczajace sceny
	scene->getRootNode()->refreshAbsoluteTransformation(true);

	// pobierz stan wejscia
	InputManager::State inputState = Game::getInputManager()->getState();

	// oblicz wektor sily na podstawie stanu wejscia
	float forward = inputState.up - inputState.down;
	float right = inputState.right - inputState.left;
	Vector force =
		Game::getGraphics()->getCamera()->getForwardVector() * forward +
		Game::getGraphics()->getCamera()->getRightTurnVector() * right;
	Matrix trans = playerNode->getParentNode()->getAbsoluteTransformation();
	trans.setTranslation(Vector(0, 0, 0));
	//force = trans * force;
	//force += Vector(0, 0.2, 0);
	force /= 3.0f;

	// rysuj scene
	scene->drawAll();

	// sprawdz kolizje
	//force = checkPhysics(force);
	Vector deltaPosition(force.getX(), force.getZ(), force.getY());
	//deltaPosition = checkPhysics(deltaPosition);
	//deltaPosition /= 5.0f;

	// oblicz katy obroty kulki
	Vector deltaRotation(deltaPosition.getY() * 0.5f, -deltaPosition.getX() * 0.5f, 0);

	// obroc i przemiesc kulke
	playerNode->setLocalTransformation(
		Matrix().setRotation(deltaRotation) *
		playerNode->getLocalTransformation());
	playerNode->getParentNode()->addTransformation(
		Matrix().setTranslation(deltaPosition));

}

/**
 * Laduje zasob.
 */
bool Level::load()
{
	// zaladuj scene
	if(!scene->loadFromResourceData(getData(), getDataSize()))
	{
		OutputDebugString("Nie udalo sie zaladowac poziomu!\n");
		return false;
	}

	// odswierz macierze bezwzgl. transf.
	scene->getRootNode()->refreshAbsoluteTransformation(true);

	// znajdz spawnpoint
	SceneNode* spawnPoint = scene->getSubNodeFromFlag(SceneNode::SpawnPoint);
	if(!spawnPoint)
	{
		OutputDebugString("Brak wezla SpawnPoint!\n");
		return false;
	}

	// dodaj kulke
	SceneNode* node = new SceneNode(spawnPoint->getParentNode(), std::string("player"));
	spawnPoint->getParentNode()->addSubNode(node);

	playerNode = new MeshSceneNode(node, std::string("player_mesh"));
	node->addSubNode(playerNode);

	Mesh* playerMesh = (Mesh*)Game::getResourceManager()->getResourceByName("models/ball-textured.x");
	if(!playerMesh)
		playerMesh = (Mesh*)Game::getResourceManager()->addResource("models/ball-textured.x", Resource::MeshResource);
	if(!playerMesh)
	{
		OutputDebugString("Nie udalo sie zaladowac modelu kulki!\n");
		return false;
	}
	((MeshSceneNode*)playerNode)->setMesh(playerMesh);
	node->setLocalTransformation(spawnPoint->getLocalTransformation());

	// oteksturuj kulke
	Texture* playerTexture = (Texture*)Game::getResourceManager()->getResourceByName("textures/cellwall.jpg");
	if(!playerTexture)
		playerTexture = (Texture*)Game::getResourceManager()->addResource("textures/cellwall.jpg", Resource::TextureResource);
	if(!playerTexture)
	{
		OutputDebugString("Nie udalo sie zaladowac tekstury kulki!\n");
		return false;
	}
	playerMesh->setSubsetTexture(0, playerTexture);

	// nie bedziemy juz uzywac tych zasobow tutaj
	playerMesh->release();
	playerTexture->release();

	// ustaw kamere na kulke
	Game::getGraphics()->getCamera()->reset();
	Game::getGraphics()->getCamera()->setReferenceNode(playerNode);

	return true;
}

/**
 * ...
 */
void Level::unload()
{
}


/**
 * Sprawdza kolizje.
 *
 * @param force Sila dzialajaca na kulke
 * @return Przesuniecie wynikowe kulki
 */
Vector Level::checkPhysics(Vector force)
{
	//return force;
	
	Vector playerPosition, playerVelocity, playerFinalPosition;
	Physics* physics = Game::getPhysics();
	Vector sc = playerNode->getAbsoluteTransformation().getScale();
	float playerRadius = 0.048500001f;//sc.getX();
	//if(playerRadius != 0.048500001f)
	//	return force;

	BoundingBox playerBox = playerNode->getBoundingBox();
	playerPosition = playerBox.getCenter();
	playerVelocity = force;

	// powieksz troche bryle gracza dla sprawdzenia potencjalnych kolizji
	Vector halfExtent = playerBox.getExtent() * 0.25f;
	playerBox.getMinPoint() -= halfExtent;
	playerBox.getMaxPoint() += halfExtent;
	//Game::getGraphics()->drawWireframeBox(playerBox.getMinPoint(),
	//	playerBox.getMaxPoint());

	//Game::getGraphics()->drawWireframeBox(playerPosition, playerPosition+playerVelocity);

	physics->resetStats();
	Physics::CollisionPacket col = Physics::CollisionPacket(
		playerPosition / playerRadius,
		playerVelocity / playerRadius);
	do
	{
		scene->getRootNode()->checkCollision(playerBox, playerRadius, col);
	} while(!physics->doResponse(col));

	/*
	char buf[128];
	sprintf(buf, "Checks: %d",
		physics->getStats().polygonsChecked
		);
	Game::getGraphics()->drawText(0, 0, buf);
	sprintf(buf, "Rejects: %d BB, %d BS, %d FF",
		physics->getStats().polysRejectedInBoundingBoxCheck,
		physics->getStats().polysRejectedInBoundingSphereCheck,
		physics->getStats().polysRejectedInFrontFaceTest
		);
	Game::getGraphics()->drawText(0, 40, buf);
	*/
	playerFinalPosition = col.finalPosition * playerRadius;
	Game::getGraphics()->drawWireframeBox(playerPosition, playerFinalPosition);

	return playerFinalPosition - playerPosition;
	
}
